package com.ruoyi.video.utils;

import com.arcsoft.face.*;
import com.arcsoft.face.enums.DetectMode;
import com.arcsoft.face.enums.DetectOrient;
import com.arcsoft.face.enums.ErrorInfo;
import com.arcsoft.face.enums.ImageFormat;
import com.arcsoft.face.toolkit.ImageFactory;
import com.arcsoft.face.toolkit.ImageInfo;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.utils.file.FileUploadUtils;
import com.ruoyi.video.domain.VImage;
import com.ruoyi.video.service.IVImageService;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @Author: orange
 * @CreateTime: 2025-01-16
 */
@Slf4j
@Component
public class ArcFaceEngineUtil {

    @Value("${arcFace.appId}")
    public String appId;

    @Value("${arcFace.sdkKey}")
    public String sdkKey;

    int errorCode;

    String projectPath = System.getProperty("user.dir");

    @Autowired
    private IVImageService ivImageService;

    FaceEngine faceEngine = new FaceEngine(projectPath+"\\ruoyi-video\\src\\main\\resources\\libs\\WIN64");

    private final AtomicLong lastSaveTime = new AtomicLong(0);  // 记录上次保存的时间戳

    private static final long SAVE_INTERVAL = 10 * 1000; // 10 秒的间隔

    /**
     * 初始化
     */
    @PostConstruct
    public void init() {
        this.errorCode = this.faceEngine.activeOnline(this.appId, this.sdkKey);
        if (this.errorCode != ErrorInfo.MOK.getValue() && this.errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
            log.error("引擎激活失败");
        }

        ActiveFileInfo activeFileInfo = new ActiveFileInfo();
        this.errorCode = this.faceEngine.getActiveFileInfo(activeFileInfo);
        if (this.errorCode != ErrorInfo.MOK.getValue() && this.errorCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue()) {
            log.error("获取激活文件信息失败");
        }

        EngineConfiguration engineConfiguration = new EngineConfiguration();
        engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
        engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_ALL_OUT);
        engineConfiguration.setDetectFaceMaxNum(10);
        engineConfiguration.setDetectFaceScaleVal(16);
        FunctionConfiguration functionConfiguration = new FunctionConfiguration();
        functionConfiguration.setSupportAge(true);
        functionConfiguration.setSupportFace3dAngle(true);
        functionConfiguration.setSupportFaceDetect(true);
        functionConfiguration.setSupportFaceRecognition(true);
        functionConfiguration.setSupportGender(true);
        functionConfiguration.setSupportLiveness(true);
        functionConfiguration.setSupportIRLiveness(true);
        engineConfiguration.setFunctionConfiguration(functionConfiguration);
        this.errorCode = this.faceEngine.init(engineConfiguration);
        if (this.errorCode != ErrorInfo.MOK.getValue()) {
            log.error("初始化引擎失败");
        }

        log.info("------------------------");
        log.info("ruoyi-video初始化引擎成功");
        log.info("微信： chenbai0511");
        log.info("请我喝杯咖啡吧qwq");
        log.info("------------------------");

    }

    /**
     * Frame对象转换为ImageInfo对象
     * @param frame
     * @return
     */
    public ImageInfo frameToImageInfo(Frame frame) {
        if (frame == null || frame.image == null) {
            log.error("Frame是空或非图像帧------");
            return null;
        } else {
            Java2DFrameConverter converter = new Java2DFrameConverter();
            BufferedImage image = converter.convert(frame);
            if (image == null) {
                log.error("Converted image is null");
                return null;
            } else {
                int width = image.getWidth();
                int height = image.getHeight();
                byte[] imageData = ((DataBufferByte)image.getRaster().getDataBuffer()).getData();
                ImageInfo imageInfo = new ImageInfo();
                imageInfo.setWidth(width);
                imageInfo.setHeight(height);
                imageInfo.setImageFormat(ImageFormat.CP_PAF_BGR24);
                imageInfo.setImageData(imageData);
                return imageInfo;
            }
        }
    }

    /**
     * 虹软检测代码
     * @param imageInfo
     * @return
     */
    public HashMap<String, Object> getUserInfo(ImageInfo imageInfo) {
        ImageInfo imageInfoFc = ImageFactory.getRGBData(new File("D:\\cat\\fc.jpg"));
        List<FaceInfo> faceInfoListFc = new ArrayList();
        this.faceEngine.detectFaces(imageInfoFc.getImageData(), imageInfoFc.getWidth(), imageInfoFc.getHeight(), imageInfoFc.getImageFormat(), faceInfoListFc);
        if (faceInfoListFc.isEmpty()) {
            log.error("未检测到人脸（faceInfoListFc）");
            return null;
        } else {
            FaceFeature faceFeatureFc = new FaceFeature();
            this.faceEngine.extractFaceFeature(imageInfoFc.getImageData(), imageInfoFc.getWidth(), imageInfoFc.getHeight(), imageInfoFc.getImageFormat(), (FaceInfo)faceInfoListFc.get(0), faceFeatureFc);
            List<FaceInfo> faceInfoList = new ArrayList();
            this.errorCode = this.faceEngine.detectFaces(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList);
            if (faceInfoList.isEmpty()) {
                log.error("未检测到人脸（faceInfoList）");
                return null;
            } else {
                FaceFeature faceFeature = new FaceFeature();
                this.faceEngine.extractFaceFeature(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), (FaceInfo)faceInfoList.get(0), faceFeature);
                FaceFeature targetFaceFeature = new FaceFeature();
                targetFaceFeature.setFeatureData(faceFeatureFc.getFeatureData());
                FaceFeature sourceFaceFeature = new FaceFeature();
                sourceFaceFeature.setFeatureData(faceFeature.getFeatureData());
                FaceSimilar faceSimilar = new FaceSimilar();
                this.faceEngine.compareFaceFeature(targetFaceFeature, sourceFaceFeature, faceSimilar);
                System.out.println("相似度：" + faceSimilar.getScore());
                if (faceSimilar.getScore() < 0.8F) {
                    this.saveImage(imageInfo);
                }

                this.errorCode = this.faceEngine.setLivenessParam(0.5F, 0.7F);
                FunctionConfiguration configuration = new FunctionConfiguration();
                configuration.setSupportAge(true);
                configuration.setSupportFace3dAngle(true);
                configuration.setSupportGender(true);
                configuration.setSupportLiveness(true);
                this.errorCode = this.faceEngine.process(imageInfo.getImageData(), imageInfo.getWidth(), imageInfo.getHeight(), imageInfo.getImageFormat(), faceInfoList, configuration);
                HashMap<String, Object> map = new HashMap();
                List<GenderInfo> genderInfoList = new ArrayList();
                this.errorCode = this.faceEngine.getGender(genderInfoList);
                if (!genderInfoList.isEmpty()) {
                    System.out.println("性别：" + ((GenderInfo)genderInfoList.get(0)).getGender());
                    map.put("gender", ((GenderInfo)genderInfoList.get(0)).getGender());
                } else {
                    log.error("未获取到性别信息");
                }

                List<AgeInfo> ageInfoList = new ArrayList();
                this.errorCode = this.faceEngine.getAge(ageInfoList);
                if (!ageInfoList.isEmpty()) {
                    System.out.println("年龄：" + ((AgeInfo)ageInfoList.get(0)).getAge());
                    map.put("age", ((AgeInfo)ageInfoList.get(0)).getAge());
                } else {
                    log.error("未获取到年龄信息");
                }

                List<Face3DAngle> face3DAngleList = new ArrayList();
                this.errorCode = this.faceEngine.getFace3DAngle(face3DAngleList);
                if (!face3DAngleList.isEmpty()) {
                    PrintStream var10000 = System.out;
                    float var10001 = ((Face3DAngle)face3DAngleList.get(0)).getPitch();
                    var10000.println("3D角度：" + var10001 + "," + ((Face3DAngle)face3DAngleList.get(0)).getRoll() + "," + ((Face3DAngle)face3DAngleList.get(0)).getYaw());
                    map.put("3DAngle", face3DAngleList.get(0));
                } else {
                    log.error("未获取到3D角度信息");
                }

                List<LivenessInfo> livenessInfoList = new ArrayList();
                this.errorCode = this.faceEngine.getLiveness(livenessInfoList);
                if (!livenessInfoList.isEmpty()) {
                    System.out.println("活体：" + ((LivenessInfo)livenessInfoList.get(0)).getLiveness());
                    map.put("liveness", ((LivenessInfo)livenessInfoList.get(0)).getLiveness());
                } else {
                    log.error("未获取到活体信息");
                }

                return map;
            }
        }
    }

    /**
     * 保存图片
     * @param imageInfo
     */
    private void saveImage(ImageInfo imageInfo) {
        long currentTime = System.currentTimeMillis();
        long lastTime = lastSaveTime.get();

        if (currentTime - lastTime < SAVE_INTERVAL) {
            log.info("10 秒内已保存过照片，跳过本次保存");
            return;
        }

        if (!lastSaveTime.compareAndSet(lastTime, currentTime)) {
            return;
        }

            try {
                File dir = new File("D:\\cat");
                if (!dir.exists()) {
                    dir.mkdirs();
                }
                String fileName = "image_" + currentTime + ".jpg";
                File outputFile = new File(dir, fileName);
                BufferedImage bufferedImage = this.convertImageInfoToBufferedImage(imageInfo);
                if (bufferedImage != null) {
                    ImageIO.write(bufferedImage, "jpg", outputFile);
                    log.info("图片已保存：{}", outputFile.getAbsolutePath());
                    String filePath = RuoYiConfig.getUploadPath();
                    MultipartFile multipartFile = new CustomMultipartFile(outputFile, "image/jpeg");
                    String file_name = FileUploadUtils.upload(filePath, multipartFile);
                    VImage vImage = new VImage();
                    vImage.setImageName(file_name);
                    vImage.setImageData(fileName);
                    this.ivImageService.insertVImage(vImage);
                } else {
                    log.error("无法转换 ImageInfo 为 BufferedImage");
                }
            } catch (IOException var16) {
                log.error("保存图片失败：{}", var16.getMessage(), var16);
            }
    }

    /**
     * 将ImageInfo转换为BufferedImage
     * @param imageInfo
     * @return
     */
    private BufferedImage convertImageInfoToBufferedImage(ImageInfo imageInfo) {
        if (imageInfo != null && imageInfo.getImageData() != null) {
            if (imageInfo.getImageFormat() == ImageFormat.CP_PAF_BGR24) {
                int width = imageInfo.getWidth();
                int height = imageInfo.getHeight();
                byte[] imageData = imageInfo.getImageData();
                BufferedImage bufferedImage = new BufferedImage(width, height, 5);
                byte[] targetPixels = ((DataBufferByte)bufferedImage.getRaster().getDataBuffer()).getData();
                System.arraycopy(imageData, 0, targetPixels, 0, imageData.length);
                return bufferedImage;
            } else {
                log.error("不支持的图像格式：{}", imageInfo.getImageFormat());
                return null;
            }
        } else {
            log.error("ImageInfo 或 imageData 为空");
            return null;
        }
    }

}
